/*
 ============================================================================
 Name        : blindSearch.c
 Author      : Petko Fiziev
 Version     :
 Copyright   : Your copyright notice
 Description : Blind Search for pattern that come from a fasta file
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>


#include "DIGEST_V2/SuffixTree.h"
#include "DIGEST_V2/ExactSearch.h"

#include "utils.h"

extern int maxOccurences;
extern DividerElement* dividers;
extern unsigned int totalDividers;


int ANGS_blindSearch(	STNode* tree, 
						char *pattern,
						int patternLength, 
						ResultRecord *occurences, 
						int *count, 
						char *pattern01) {
	
	int binaryPatternLength = 2*patternLength;
	
	int depth=0;
	int stindex;
	
	int fileNumber;
	int binaryStartPos;
	int depth1 = depth;
	
		
					
	
	
	*count = 0;
	
	
	//1. Perform blind search
	
	stindex=blindSearch(pattern01, binaryPatternLength, tree, &depth);
	if(stindex==-1)
	{
		//fprintf(stderr, "Pattern not found (blind search)\n");
		return 0;
	}
	
	//2. Find first leaf
	fileNumber=0;
	binaryStartPos=0;
	depth1=depth;
	findFirstLeaf(tree, stindex, &fileNumber, &binaryStartPos, &depth1,binaryPatternLength);
	
	//3. Find all occurences	
	collectAllLeaves(tree, stindex, count, occurences ,binaryPatternLength, depth);
	
	return 0;	
}






int main(int argc, char *argv[]) 
{

	int i;
	char inputfilenameprefix [MAX_PATH_LENGTH];
	char dividersFileName[MAX_PATH_LENGTH];
	char treeprefix [MAX_PATH_LENGTH];
	char treeFileName[MAX_PATH_LENGTH];
	FILE *treeFile;
	ResultRecord *occurences;
	int count = 0;
	int total_count = 0;
	char *encodedDNA;
	char *buffer;
	FILE *dividersFile;
	STNode* tree = NULL;
	
	if(argc<5)
	{
		fprintf(stderr, "To run: %s <treefolder> <treefileprefix> <sortReads_output> <maximum_occurences>\n", argv[0]);
		return 1;
	}

	//Load dividers
	sprintf(inputfilenameprefix,"%s%s", argv[1], argv[2]);
	sprintf(treeprefix,"%s%s_tree", argv[1], argv[2]);
	
	sprintf(dividersFileName,"%s_dividers",inputfilenameprefix);
	
	if(!(dividersFile= fopen ( dividersFileName , "rb" )))
	{
		fprintf(stderr, "Could not open dividers DNA file \"%s\" \n", dividersFileName);
		return 1;
	}
	
	//determine number of dividers
	fseek (dividersFile, 0, SEEK_END);
	totalDividers=ftell (dividersFile)/sizeof(DividerElement);
	rewind(dividersFile);
	
	dividers=(DividerElement*) calloc (totalDividers, sizeof(DividerElement));
	
	if(fread (dividers,sizeof(DividerElement),totalDividers,dividersFile)!=totalDividers)
	{
		fprintf(stderr, "Error reading tree dividers file \"%s\" \n", dividersFileName);
		return 1;
	}

	fclose(dividersFile);
	
	// find the longest suffix tree
	int maxTreeNodes = 0;
	for (i = 0; i < totalDividers; i++) {
		maxTreeNodes = MAX(dividers[i].length, maxTreeNodes);
		//printf("DIVIDER: %u %u %d %d\n", dividers[i].minBitSequence, dividers[i].maxBitSequence, dividers[i].fileNumber,dividers[i].length);
		}
	fprintf(stderr, "%d divider elements\n", totalDividers);

	tree = (STNode*) calloc (maxTreeNodes, sizeof(STNode));
		


	FILE *file = fopen((const char*)argv[3],"rb");
	/*Check for validity of the file.*/
	if(file == 0) {
		fprintf(stderr,"can't open file: %s.\n", argv[3]);	
		return 1;
	}	

	char outputfilename[MAXLINE];
	sprintf(outputfilename, "%s.blindSearch", argv[3]);
	FILE *output = fopen(outputfilename,"wb");
	if(output == 0) {
		fprintf(stderr,"can't open file: %s.\n", outputfilename);	
		return 1;
	}	

	
	maxOccurences= atoi(argv[4]);	
	
	occurences=(ResultRecord*) calloc (maxOccurences, sizeof(ResultRecord));
	encodedDNA=(char*) calloc (2*MAXLINE, sizeof(char));
	buffer=(char*) calloc (MAXLINE, sizeof(char));
	
	
	
	int treeFileNumber = 0;	
	int foundTree = 0;
	unsigned int bitPrefix;
	
	int total_sequences;
	
	if (fread(&total_sequences, sizeof(int),1, file) != 1) {
		fprintf(stderr,"cannot read from %s\n", argv[3]);
		return 1;
		}
	fprintf(stderr,"total sequences: %d\n", total_sequences);
	
	int total_bitseq_length;
	if (fread(&total_bitseq_length, sizeof(int),1, file) != 1) {
		fprintf(stderr,"cannot read from %s\n", argv[3]);
		return 1;
		}
	fprintf(stderr,"total bitseq length: %d\n", total_bitseq_length);
	fprintf(stderr,"maximum occurences: %d\n", maxOccurences);
	
	
	
	long seq_id;
	int seq_real_length;
	WORD bitseq[MAXLINE] = {0};	
	char charseq[MAXLINE] = {0};
	int bitseqlen = 0;
	start_watch();
	fprintf(stderr, "blind searching in tree: ");
	while(fread(&seq_id, sizeof(long), 1, file) == 1) {
		if(fread(&seq_real_length, sizeof(int), 1, file) != 1) {
			fprintf(stderr,"cannot read from %s\n", argv[3]);
			return 1;
		}
		bitseqlen = blen(seq_real_length);
		if(fread(&bitseq, sizeof(WORD), bitseqlen, file) != bitseqlen) {
			fprintf(stderr,"cannot read from %s\n", argv[3]);
			return 1;
		}
		
		bitseq2char(bitseq, seq_real_length, charseq);
		//printf(">%ld\n%s\n", seq_id, charseq);
		get01Encoding(charseq, seq_real_length, encodedDNA);	
		//3. We need a binary prefix of length 32 - to locate dividers
		bitPrefix = getBitPrefix(encodedDNA, 2*seq_real_length);
		//fprintf(stderr,"bitprefix: %u\n", bitPrefix);
		
		//4. Locate 1-2 trees to be searched - for now suppose 1 tree		
		
		while (treeFileNumber < totalDividers) {				
			if(	dividers[treeFileNumber].minBitSequence <= bitPrefix && 
				bitPrefix <= dividers[treeFileNumber].maxBitSequence ) {
				if ( !foundTree ) {
					//5. Open and read suffix tree file
					
					sprintf(treeFileName,"%s_%i",treeprefix,treeFileNumber);
					fprintf(stderr,"%d ", treeFileNumber);
					if(!(treeFile = fopen ( treeFileName , "rb" ))) {
						fprintf(stderr, "Could not open suffix tree file \"%s\" \n", treeFileName);
						return 1;
					}
					
					
					int totalNodes = dividers[treeFileNumber].length;								
					if(fread (tree, sizeof(STNode), totalNodes, treeFile) != totalNodes) {
						fprintf(stderr, "Error loading tree from file \"%s\" \n", treeFileName);
						return 1;
					}
					
		
					
					
					fclose(treeFile);
					fprintf(stderr, ", ");					
					foundTree = 1;
				}
				break; 
			}
			else if ( 	treeFileNumber < totalDividers - 1 && 
						dividers[treeFileNumber].maxBitSequence > bitPrefix &&
						dividers[treeFileNumber+1].minBitSequence < bitPrefix ) {
				foundTree = 0;
				break;
				}
			
			treeFileNumber++;
			foundTree = 0;
		}
		
		
		
		
		// perform the search		
		
		if(ANGS_blindSearch(tree, charseq, seq_real_length, occurences, &count, encodedDNA))
			return 1;
		
		
		
		fwrite(&seq_id, sizeof(long), 1, output);		
		fwrite(&seq_real_length, sizeof(int), 1, output);
		fwrite(bitseq, sizeof(WORD), bitseqlen, output);
		fwrite(&count, sizeof(int), 1, output);
		int to_ouput = MIN(maxOccurences, count);
		
		if (to_ouput > 0) { 
			fwrite(occurences, sizeof(ResultRecord), to_ouput, output);			 
		}
		
		
		
		total_count += to_ouput;
	}
	fprintf(stderr, "done | ");					
	stop_watch();
	fwrite(&total_sequences, sizeof(int), 1, output);	
	fwrite(&total_bitseq_length, sizeof(int), 1, output);	
	fwrite(&total_count, sizeof(int), 1, output);
		
	fclose(file);  
	fclose(output);
	
	return 0;
}
